2009-07-26 5 views
73

Conosco tutte le discussioni sul perché non si dovrebbero leggere/scrivere file dal kernel, invece come usare/proc o netlink per farlo. Voglio leggere/scrivere comunque. Ho anche letto Driving Me Nuts - Things You Never Should Do in the Kernel.Come leggere/scrivere file all'interno di un modulo del kernel di Linux?

Tuttavia, il problema è 2.6.30 non esporta sys_read(). Piuttosto è avvolto in SYSCALL_DEFINE3. Quindi, se uso che nel mio modulo, ottengo seguenti avvertenze:

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

Ovviamente insmod non può 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 esportate)?
  • In generale, come utilizzare le chiamate di sistema racchiuse nella macro SYSCALL_DEFINEn() dal kernel?

risposta

94

Si dovrebbe essere consapevoli del fatto che si dovrebbe evitare l'I/O del file quando possibile. L'idea principale è quella di andare "un livello più profondo" e chiamare VFS level functions 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 per aprire):

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 di dati da un file (simile a prea d):

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

La scrittura di dati in 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; 
} 

Sincronizzazione cambia un file (simile a fsync):

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

[Edit] In origine, Ho proposto di usare file_fsync, che è andato nelle versioni più recenti del kernel. Grazie al povero ragazzo che ha suggerito il cambiamento, ma il cui cambiamento è stato respinto. 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à, c'è un modo per usare le chiamate di sistema dichiarate usando SYSCALL_DEFINE? – Methos

+5

Ho provato questo codice nel kernel 2.6.30 (Ubuntu 9.04) e ho letto il file in crash del sistema. Qualcuno ha riscontrato lo stesso problema? –

+0

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