Odczyt / zapis plików w module jądra Linuksa

99

Znam wszystkie dyskusje o tym, dlaczego nie powinno się czytać / zapisywać plików z jądra, zamiast tego jak używać / proc lub netlink do tego. Mimo wszystko chcę czytać / pisać. Przeczytałem także Driving Me Nuts - Things You Never Powinieneś robić w jądrze .

Jednak problem polega na tym, że 2.6.30 nie eksportuje sys_read(). Raczej jest zapakowany SYSCALL_DEFINE3. Więc jeśli używam go w swoim module, otrzymuję następujące ostrzeżenia:

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

Oczywiście insmodnie można załadować modułu, ponieważ łączenie nie przebiega poprawnie.

Pytania:

  • Jak czytać / pisać w jądrze po wersji 2.6.22 (gdzie sys_read()/ sys_open()nie są eksportowane)?
  • Ogólnie, jak używać wywołań systemowych opakowanych w makro SYSCALL_DEFINEn()z poziomu jądra?
Methos
źródło

Odpowiedzi:

122

Powinieneś być świadomy, że powinieneś unikać wejścia / wyjścia plików z jądra Linuksa, jeśli to możliwe. Głównym pomysłem jest pójście „o jeden poziom głębiej” i bezpośrednie wywołanie funkcji poziomu VFS zamiast obsługi wywołania systemowego :

Obejmuje:

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

Otwieranie pliku (podobnie jak otwieranie):

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

Zamknij plik (podobnie do zamknięcia):

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

Odczytywanie danych z pliku (podobnie do 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;
}   

Zapisywanie danych do pliku (podobnie do 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;
}

Synchronizacja zmienia plik (podobnie do fsync):

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

[Edytuj] Początkowo zaproponowałem użycie file_fsync, który zniknął w nowszych wersjach jądra. Dzięki biednemu facetowi, który sugerował zmianę, ale którego zmiana została odrzucona. Zmiana została odrzucona, zanim mogłem ją sprawdzić.

dmeister
źródło
2
Dziękuję Ci. Myślałem o zrobieniu czegoś podobnego, replikując funkcjonalność sys_read / sys_open. Ale to jest wielka pomoc. Ciekawostka, czy istnieje sposób na użycie wywołań systemowych zadeklarowanych przy użyciu SYSCALL_DEFINE?
Methos
5
Wypróbowałem ten kod w jądrze 2.6.30 (Ubuntu 9.04) i odczytanie pliku powoduje awarię systemu. Czy ktoś napotkał ten sam problem?
Enrico Detoma
@Enrico Detoma? Och, wow. Czy w jakiś sposób możesz mi dać moduł, którego użyłeś? Nigdy wcześniej tego nie widziałem?
dmeister
2
To natychmiast rodzi pytanie „dlaczego robisz ten taniec FS, btw”, na które całkiem ładną odpowiedź znajduje się tutaj: linuxjournal.com/node/8110/print w sekcji „Naprawianie przestrzeni adresowej”.
PypeBros
@dmeister, Nie znaleziono obiektu dla funkcji poziomu VFS łącza ur
sree
19

Od wersji 4.14 jądra Linuksa funkcje vfs_readi vfs_writefunkcje niejuż eksportowane do użytku w modułach. Zamiast tego dostępne są funkcje wyłącznie dla dostępu do plików jądra:

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

Ponadto filp_opennie akceptuje już ciągu znaków przestrzeni użytkownika, więc może być używany do bezpośredniego dostępu do jądra (bez tańca z set_fs).

Tsyvarev
źródło