Leggere / scrivere file all'interno di un modulo del kernel Linux


99

Conosco tutte le discussioni sul perché non si dovrebbero leggere / scrivere file dal kernel, invece come usare / proc o netlink per farlo. Voglio comunque leggere / scrivere. Ho anche letto Driving Me Nuts - Cose che non dovresti mai fare nel kernel .

Tuttavia, il problema è che 2.6.30 non esporta sys_read(). Piuttosto è avvolto SYSCALL_DEFINE3. Quindi, se lo uso nel mio modulo, ricevo i seguenti avvisi:

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

Ovviamente insmodnon è possibile caricare il modulo perché il collegamento non avviene correttamente.

Domande:

  • Come leggere / scrivere all'interno del kernel dopo 2.6.22 (dove sys_read()/ sys_open()non vengono esportati)?
  • In generale, come utilizzare le chiamate di sistema racchiuse in macro SYSCALL_DEFINEn()dall'interno del kernel?

Risposte:


122

Dovresti essere consapevole che dovresti evitare l'I / O di file dal kernel Linux quando possibile. L'idea principale è di andare "un livello più in profondità" e chiamare le funzioni di livello VFS invece del gestore syscall direttamente:

Include:

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

Apertura di un file (simile a open):

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

Chiudere un file (simile alla chiusura):

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

Lettura dei dati da un file (simile a 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;
}   

Scrittura di dati su un file (simile a 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 sincronizzazione modifica un file (simile a fsync):

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

[Modifica] Inizialmente, ho proposto di utilizzare file_fsync, che è andato nelle versioni più recenti del kernel. Grazie al poveretto che ha suggerito il cambiamento, ma il cui cambiamento è stato rifiutato. La modifica è stata rifiutata prima che potessi esaminarla.


2
Grazie. Stavo pensando di fare qualcosa di simile replicando la funzionalità sys_read / sys_open. Ma questo è un grande aiuto. Una curiosità, esiste un modo per utilizzare le chiamate di sistema dichiarate utilizzando SYSCALL_DEFINE?
Methos

5
Ho provato questo codice nel kernel 2.6.30 (Ubuntu 9.04) e la lettura del file blocca il sistema. Qualcuno ha riscontrato lo stesso problema?
Enrico Detoma

@Enrico Detoma? Oh, wow. In questo modo puoi darmi il modulo che hai usato? Mai visto prima?
dmeister

2
Ciò solleva immediatamente la domanda "perché stai facendo quella danza FS, btw", a cui si risponde abbastanza bene qui: linuxjournal.com/node/8110/print nella sezione "Correzione dello spazio degli indirizzi".
PypeBros

@dmeister, oggetto non trovato per le funzioni di livello VFS del collegamento ur
sree

20

Dalla versione 4.14 del kernel Linux vfs_reade le vfs_writefunzioni non vengono più esportate per l'uso nei moduli. Vengono invece fornite funzioni esclusivamente per l'accesso ai file del kernel:

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

Inoltre, filp_opennon accetta più la stringa dello spazio utente, quindi può essere utilizzato direttamente per l'accesso al kernel (senza ballare set_fs).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.